package com.chatplus.application.common.config;

import com.chatplus.application.common.logging.SouthernQuietLogger;
import com.chatplus.application.common.logging.SouthernQuietLoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Spring 异步配置。
 */
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
    private static final SouthernQuietLogger LOGGER = SouthernQuietLoggerFactory.getLogger(AsyncConfig.class);

    /**
     * 核心线程数
     */
    @Value("${async.executor.thread.core_pool_size:10}")
    private int corePoolSize;

    /**
     * 最大线程数
     */
    @Value("${async.executor.thread.max_pool_size:50}")
    private int maxPoolSize;

    /**
     * 线程池维护线程所允许的空闲时间
     */
    @Value("${async.executor.thread.keep_alive_seconds:300}")
    private int keepAliveSeconds;

    /**
     * 队列最大长度
     */
    @Value("${async.executor.thread.queue_capacity:1000}")
    private int queueCapacity;

    @Override
    @Bean(name = "getAsyncExecutor")
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(corePoolSize);
        //配置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        //配置队列大小
        executor.setQueueCapacity(queueCapacity);
        executor.setRejectedExecutionHandler((Runnable r, ThreadPoolExecutor exe) ->
                LOGGER.message("当前任务线程池队列已满.").warn());
        // rejection-policy：当pool已经达到max size的时候，如何处理新任务
        // CALLER_RUNS：不在新线程中执行任务，而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (ex, method, params) -> LOGGER
                .message("线程池执行任务发生未知异常.")
                .context("method", method)
                .context("params", params)
                .exception(ex)
                .error();
    }
}

